<?php
/**
 * Chinapnr.class.php 汇付天下-帐管家接口
 * ==============================================
 * Copy right
 * ----------------------------------------------
 * ==============================================
 * @author: 陈聪
 * @date: 2016年11月1日
 * @version: v1.0.0
 */
namespace Service\Pay\Chinapnr;
defined('THINK_PATH') or exit();
use Service\Pay;
class Chinapnr  extends Pay {
    protected $_errCode=array(
        '0'=>'本次调用成功',
        '-100'=>'环境变量"NPCDIR"未设置 需要在在Linux或Unix上设置环境变量NPCDIR',
        '-101'=>'商户密钥文件不存在或无法打开 设置密钥文件为可写方式',
        '-102'=>'密钥文件格式错误 可能商户的密钥文件在传输途中有误',
        '-103'=>'参数错误 请检查参与签名的参数是否正确',
        '-112'=>'公钥文件不存在或无法打开 设置密钥文件为可写方式',
        '-113'=>'公钥文件格式错误 可能公钥文件在传输途中有误',
        '-301'=>'验证签名出错 请检查参与签名的参数是否正确',
        '-401'=>'参与签名的数据体超过规定长度',
        '101000' => '交易成功',
        '101003' => '交易失败',
        '101099' => '系统异常',
        '101100' => '请求参数非法',
        '101101' => '商户无此接口权限',
        '101102' => '验证签名失败',
        '101103' => '商户状态异常',
        '101106' => '商户签名未配置',
        '101202' => '交易订单号重复',
        '101203' => '账户可用余额不足',
        '101204' => '商户配置异常',
        '101205' => '短信验证码验证失败',
        '101206' => '短信验证码发送手机号与验证手机号不一致',
        '101207' => '短信验证码或短信唯一标识为空',
        '101208' => '短信验证码已失效请重新获取',
        '101209' => '验证码发送接口与接口不一致',
        '101301' => '该用户已开户，身份证号已存在',
        '101302' => '该用户已开户，手机号已存在',
        '101303' => '该用户正在开户中，请勿重复申请',
        '101304' => '个人用户开户失败',
        '101400' => '身份证和姓名校验不符',
        '101401' => '身份证末位校验失败',
        '103000' => '交易成功',
        '103002' => '请求已受理',
        '103003' => '交易失败',
        '103099' => '系统异常',
        '103100' => '请求参数非法',
        '103101' => '商户无此接口权限',
        '103102' => '验证签名失败',
        '103103' => '商户状态异常',
        '103104' => '用户状态异常',
        '103106' => '商户签名未配置',
        '103201' => '页面数据被篡改',
        '103202' => '交易订单号重复',
        '103203' => '账户可用余额不足',
        '103204' => '商户配置异常',
        '103205' => '短信验证码验证失败',
        '103206' => '短信验证码发送手机号与验证手机号不一致',
        '103207' => '短信验证码或短信唯一标识为空',
        '103208' => '短信验证码已失效请重新获取',
        '103209' => '验证码发送接口与接口不一致',
        '103210' => '短信验证码发送过于频繁',
        '103211' => '短信验证码发送失败',
        '103301' => '不支持绑定该银行的银行卡',
        '103302' => '用户已绑定快捷卡，不能再绑定取现卡',
        '103303' => '银行卡号与银行不匹配',
        '103304' => '该银行卡非借记卡',
        '103305' => '企业用户/商户不支持快捷绑卡',
        '103306' => '用户已绑定快捷或代扣卡，请勿重复申请',
        '103307' => '用户有快捷正在绑定中，请勿重复绑卡',
        '103308' => '省份地区信息非法',
        '103400' => '银行账号无效或不存在',
        '103401' => '持卡人身份信息或手机号验证不符',
        '103402' => '卡号长度有误',
        '103403' => '验证超时',
        '103404' => '账号应为活期账号',
        '103405' => '您的银行卡暂不支持该业务，请更换其他银行卡或咨询发卡银行',
        '105000' => '交易成功',
        '105002' => '请求已受理',
        '105099' => '系统异常',
        '105100' => '请求参数非法',
        '105101' => '商户无此接口权限',
        '105102' => '验证签名失败',
        '105103' => '商户状态异常',
        '105104' => '用户状态异常',
        '105205' => '短信验证码验证失败',
        '105206' => '短信验证码发送手机号与验证手机号不一致',
        '105207' => '短信验证码或短信唯一标识为空',
        '105208' => '短信验证码已失效请重新获取',
        '105209' => '验证码发送接口与接口不一致',
        '105300' => '短信验证码有误',
        '105301' => '用户未绑定过该卡',
        '105302' => '非代扣或快捷卡，不能解绑',
        '105303' => '订单重复',
        '105304' => '用户基本信息不存在',
        '105305' => '验证卡信息失败',
        '110000' => '交易成功',
        '110003' => '交易失败',
        '110099' => '系统异常',
        '110100' => '请求参数非法',
        '110101' => '商户无此接口权限',
        '110102' => '验证签名失败',
        '110103' => '商户状态异常',
        '110104' => '用户状态异常',
        '110106' => '商户签名未配置',
        '110202' => '交易订单号重复',
        '110204' => '商户配置异常',
        '110210' => '短信验证码发送过于频繁',
        '110211' => '短信验证码发送失败',
        '110301' => '短信验证码发送开关已关闭',
        '110304' => '快捷充值短信验证码发送失败，用户还未绑定快捷卡',
        '110305' => '非快捷绑卡银行预留手机号',
        '201000' => '交易成功',
        '201002' => '请求已受理',
        '201003' => '交易失败',
        '201099' => '系统异常',
        '201100' => '请求参数非法',
        '201101' => '商户无此接口权限',
        '201102' => '验证签名失败',
        '201103' => '商户状态异常',
        '201104' => '用户状态异常',
        '201105' => '账户状态异常',
        '201106' => '商户签名未配置',
        '201202' => '交易订单号重复',
        '201204' => '商户配置异常',
        '201205' => '短信验证码验证失败',
        '201206' => '短信验证码发送手机号与验证手机号不一致',
        '201207' => '短信验证码或短信唯一标识为空',
        '201208' => '短信验证码已失效请重新获取',
        '201209' => '验证码发送接口与接口不一致',
        '201300' => '不支持此充值银行',
        '201301' => '该充值银行网关不存在',
        '201302' => '不支持此充值类型',
        '201303' => '商户充值基础信息未配置',
        '201304' => '不支持此业务类型',
        '201305' => '入账客户信息不正确',
        '201306' => '入账分账串信息不正确',
        '201307' => '该用户未绑定快捷卡',
        '201308' => '该用户未绑定代扣卡',
        '201309' => '该用户代扣协议不存在或状态异常',
        '201310' => '企业用户或商户不支持快捷充值',
        '201311' => '企业用户或商户不支持代扣充值',
        '201312' => '手续费金额不得大于等于交易金额',
        '201313' => '该充值银行与用户快捷卡不匹配',
        '201314' => '充值手续费账户状态不正常',
        '201315' => '个人用户仅支持个人网银充值',
        '201316' => '支付失败',
        '202000' => '交易成功',
        '202002' => '请求已受理',
        '202003' => '交易失败',
        '202099' => '系统异常',
        '202100' => '请求参数非法',
        '202101' => '商户无此接口权限',
        '202102' => '验证签名失败',
        '202103' => '商户状态异常',
        '202104' => '用户状态异常',
        '202105' => '账户状态异常',
        '202106' => '商户签名未配置',
        '202202' => '交易订单号重复',
        '202204' => '商户配置异常',
        '202212' => '账户余额查询失败',
        '202300' => '银行卡不是取现卡',
        '202301' => '没有可用的默认取现卡',
        '202302' => '取现服务费超出最大费率配置',
        '202303' => '取现金额不足',
        '202304' => '取现方式错误',
        '202305' => '银行卡信息不存在或状态异常',
        '202306' => '接口不支持手续费外扣',
        '202307' => '取现金额小于等于取现费用',
        '202308' => '商户取现不支持服务费',
        '202309' => '手续费专户不能出账',
        '203000' => '交易成功',
        '203099' => '系统异常',
        '203100' => '请求参数非法',
        '203101' => '商户无此接口权限',
        '203102' => '验证签名失败',
        '203103' => '商户状态异常',
        '203104' => '用户状态异常',
        '203202' => '交易订单号重复',
        '203300' => '转账类型与转入方/转出方用户信息不匹配',
        '203301' => '转出方用户信息不存在',
        '203302' => '转入方用户信息不存在',
        '203303' => '转出方用户状态异常',
        '203304' => '转入方用户状态异常',
        '203305' => '子账户间转账，商户信息不存在',
        '203306' => '子账户间转账，商户状态异常',
        '203307' => '转出方帐户号不存在',
        '203308' => '转入方账号不存在',
        '203309' => '转出方帐户状态异常',
        '203310' => '转入方帐户状态异常',
        '203311' => '转账失败',
        '203312' => '商户手续费帐户不存在',
        '203313' => '商户手续费帐户状态异常',
        '203314' => '风控拦截',
        '203315' => '验证手续费专户，资金不能转出',
        '301000' => '交易成功',
        '301010' => '记录不存在',
        '301099' => '系统异常',
        '301100' => '请求参数非法',
        '301101' => '商户无此接口权限',
        '301102' => '验证签名失败',
        '301103' => '商户状态异常',
        '301106' => '商户签名未配置',
        '302000' => '交易成功',
        '302010' => '记录不存在',
        '302099' => '系统异常',
        '302100' => '请求参数非法',
        '302101' => '商户无此接口权限',
        '302102' => '验证签名失败',
        '302103' => '商户状态异常',
        '302106' => '商户签名未配置'
    );

    /**
     * @desc 构造函数
     * @author 陈聪
     */
    function __construct($options=array()) {
        if(empty($options)) {
            $pay_config = C('PAY_CONFIG');
            $options = isset($pay_config['Chinapnr'])?$pay_config['Chinapnr']:array();
        }
        $this->options = $options;
    }

    /**
     * @desc 获取错误描述
     * @author 陈聪
     */
    private function _getErrMsg($resp_code){
        if(isset($this->_errCode[$resp_code])){
            return $this->_errCode[$resp_code];
        }
        return $resp_code;
    }

    /**
     * @desc 请求chinapnr账管家接口
     * @author jason.zhang@chinapnr.com
     * @createDate 20160523
     * @param array $data, 请求数据
     * @param array $sequence, 返回结果验签排序用
     * @return array
     * @throws Exception
     */
    private function _requestInterface($data, $sequence) {
        $rts = $this->getCheckValue($data);
        if($rts['rt']!=1){
            return $rts;
        }
        $data['check_value']=$rts['data'];
        $ch = curl_init ();
        curl_setopt($ch, CURLOPT_URL, $this->options['asharpServer']);
        curl_setopt($ch, CURLOPT_HEADER, 0 );
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证证书下同
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //
        $return = json_decode(curl_exec($ch), true);
        curl_close($ch);

        //记录日志
        third_party_api_log($this->options['asharpServer'],$data,$return,$this->options['type']);

        if(!$return){
            $rts['rt']=-1;
            $rts['msg']="请求失败,请重试!";
            return $rts;
        }
        //验证接口返回值
        if($return['resp_code'] !== $data['cmd_id'].'000'){
            $rts['rt']=$return['resp_code'];
            $rts['msg']=$this->_getErrMsg($return['resp_code']);
            return $rts;
        }
        //验证返回参数
        $rts=$this->verifyCheckValue($return, $sequence);
        if($rts['rt']!=1){
            return $rts;
        }
        $rts['rt']=1;
        $rts['msg']="";
        $rts['data']=$return;
        return $rts;
    }

    /**
     * @desc 请求chinapnr账管家接口-此接口只负责返回相关页面输出,不做验证
     * @author jason.zhang@chinapnr.com
     * @createDate 20160523
     * @param array $data, 请求数据
     * @param array $sequence, 返回结果验签排序用
     * @return array
     */
    private function _requestInterfaceHtml($data, $referer='') {
        $rts = $this->getCheckValue($data);
        if($rts['rt']!=1){
            return $rts;
        }
        $data['check_value']=$rts['data'];
        $rts=array();
        $rts['cookie']='';
        $ch = curl_init ();
        curl_setopt($ch, CURLOPT_REFERER, $referer?$this->options['referer']:'');
        curl_setopt($ch, CURLOPT_USERAGENT, $this->options['useragent'] );
        curl_setopt($ch, CURLOPT_COOKIE, $rts['cookie'] );
        curl_setopt($ch, CURLOPT_URL, $this->options['asharpServer']);
        curl_setopt($ch, CURLOPT_HEADER, true );
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1 );
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证证书下同
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //
        $response=curl_exec($ch);
        $header='';
        $body='';
        if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200') {
            list($header, $body) = explode("\r\n\r\n", $response, 2);
        }
        curl_close($ch);
        $rts['response']=$response;
        $rts['header']=$header;
        $rts['body']=$body;

        //记录日志
        third_party_api_log($this->options['asharpServer'],$data,$response,$this->options['type']);

        $rts['rt']=1;
        $rts['msg']="";
        //处理body数据,如果是json数据返回,则解析成array
        $tmpArr = json_decode($body, true);//出现错误的时候,此处是json格式数据
        if(isset($tmpArr['cmd_id'])){
            //绑卡出现此流程,说明有错误
            $rts['rt']=$tmpArr['resp_code'];
            $rts['msg']=urldecode($tmpArr['resp_desc']);
            $rts['data']=$tmpArr;
        }
        return $rts;
    }

    /**
     * @desc 计算请求参数的md5值
     * @author jason.zhang@chinapnr.com
     * @createDate 20160523
     * @param array $data, 请求参数，须按文档序列要求排列
     * @return string, md5字符串
     */
    private function getMD5($data){
        $str = '';
        foreach($data as $k => $v) {
            if(in_array($k, ['user_name', 'div_acct_id', 'div_amt'])){
                //中文不加签，约定，但后续更改的接口有些英文也不加签，服了
                continue;
            }
            $str .= ($v);
        }
        return md5($str);
    }

    /**
     * @desc 从签名机获取签名字符串
     * @author jason.zhang@chinapnr.com
     * @date 20160523
     * @param $data, 请求参数，须按文档序列要求排列
     * @return array $rts
     */
    public function getCheckValue($data) {
        $rts=array();
        $md5 = $this->getMD5($data);
        try {
            $fp = stream_socket_client($this->options['npcServer'], $errno, $errstr, 5);
            if (!$fp) {
                $rts['rt']=$errno;
                $rts['msg']=iconv("GBK", "UTF-8//IGNORE", $errstr);
                return $rts;
            }
            $type = 'S';
            $paramVal = $type . $this->options['asharp_mer_id'] . sprintf("%04d", strlen($md5)) . $md5;
            $paramVal = sprintf("%04d", strlen($paramVal)) . $paramVal;
            fputs($fp, $paramVal);
            $chkValue = '';
            while (!feof($fp)) {
                $chkValue .= fgets($fp, 128);
            }
            fclose($fp);

            if(substr($chkValue, 0, 4) !== '0000') {
                $rts['rt']=substr($chkValue, 0, 4);
                $rts['msg']=$this->_getErrMsg($rts['rt']);
                $rts['msg']=($rts['msg']==$rts['rt']?$rts['rt']:$rts['msg']);
                return $rts;
            }
            $rts['rt']=1;
            $rts['msg']='';
            $rts['data']=substr($chkValue, -256);
        } catch (Exception $e) {
            $rts['rt']=-1;
            $rts['msg']=$e->getMessage();
        }
        return $rts;
    }

    /**
     * @desc 从签名机验证asharp返回数据是否合法
     * @author jason.zhang@chinapnr.com
     * @date 20160523
     * @param $data, 返回参数
     * @param $sequence, md5串排列顺序
     * @return array $rts
     */
    public function verifyCheckValue($data, $sequence) {
        $rts=array();
        $rts['rt']=1;
        $rts['msg']='';
        $rts['sData']=$data;
        $rts['sSequence']=$sequence;
        $verify = '';
        // 当你看到此处代码时，可想而知接口设计有多呵呵，计算md5值顺序人为指定，而不是依ascii顺序连接，这样每次都要多传一个人为指定的顺序参数
        foreach($sequence as $v) {
            $verify .= isset($data[$v]) ? urldecode($data[$v]) : '';
        }
        $verify = md5($verify);
        try {
            $fp = stream_socket_client($this->options['npcServer'], $errno, $errstr, 5);
            if (!$fp) {
                $rts['rt']=$errno;
                $rts['msg']=$this->_getErrMsg($errno);
                $rts['msg']=$rts['msg']==$errno?$errstr:$rts['msg'];
                return $rts;
            }
            $type = 'V';
            $paramVal = $type . $this->options['asharp_mer_id'] . sprintf("%04d", strlen($verify)).$verify;
            $paramVal .= $data['check_value'];
            $paramVal = sprintf("%04d", strlen($paramVal)) . $paramVal;
            fputs($fp, $paramVal);
            $response = '';
            while (!feof($fp)) {
                $response .= fgets($fp, 128);
            }
            fclose($fp);
            $rt=substr($response,0,4);
            if($rt !== "0000"){
                $rts['rt']=$rt;
                $rts['msg']="验签失败!";
            }
        } catch (Exception $e) {
            $rts['rt']=-1;
            $rts['msg']=$e->getMessages();
        }
        return $rts;
    }

    /**
     * @desc 绑卡发送短信界面进行解析-后期如果汇付修改了相关页面代码,则本方法需要跟进修改
     * @author 陈聪
     */
    private function _getHftxBindCardSmsForm($str){
        $rts=array();
        $rts['action']='';//不能改名字,前端调用需要用它来判断短信是否发送成功
        $rts['smsUrl']='';
        $rts['cookie']='';
        $rts['form']=array();
        $rts['form']['memcacheKey']='';
        $rts['form']['bankId']='';
        $rts['form']['smsCode']='';
        preg_match_all('/action="(.*?)"/i',$str,$rs);
        if(isset($rs[1])&&isset($rs[1][0])){
            $rts['action']=trim($rs[1][0]);
        }
        preg_match_all('/id="memcacheKey".*?value="(.*?)"/i',$str,$rs);
        if(isset($rs[1])&&isset($rs[1][0])){
            $rts['form']['memcacheKey']=trim($rs[1][0]);
        }
        preg_match_all('/name="bankId".*?value="(.*?)"/i',$str,$rs);
        if(isset($rs[1])&&isset($rs[1][0])){
            $rts['form']['bankId']=trim($rs[1][0]);
        }
        preg_match_all('/id="sms-submit-btn".*?data-url="(.*?)"/i',$str,$rs);
        if(isset($rs[1])&&isset($rs[1][0])){
            $rts['smsUrl']=trim($rs[1][0]);
        }
        //处理请求头,获取cookie信息
        preg_match_all('/Set-Cookie:(.*);/iU',$str, $rs);
        if(isset($rs[1])&&isset($rs[1][0])){
            $rts['cookie']=trim($rs[1][0]);
        }
        return $rts;
    }

    /**
     * @desc 绑卡结果进行解析-后期如果汇付修改了相关页面代码,则本方法需要跟进修改
     * @author 陈聪
     */
    private function _getHftxBindCardResult($str){
        $rts=array();
        $arr=array("resp_desc","bg_ret_url","fee_acct_id",
            "cmd_id","platform_seq_id","card_no","order_id",
            "user_cust_id","fee_amt","extension","bank_id",
            "resp_code","mer_priv","order_date","mer_cust_id",
            "check_value","ret_url");
        foreach($arr AS $v){
            preg_match_all('/name="'.$v.'".*?value=\'(.*?)\'/i',$str, $rs);
            if(isset($rs[1])&&isset($rs[1][0])){
                $rts[$v]=trim($rs[1][0]);
            }else{
                $rts[$v]="";
            }
        }
        return $rts;
    }

    /**
     * @desc 发送相关短信,涉及110接口
     *      注意:101和105每个用户每天只能发5次短信
     *          201每个用户每天可以发10次短信
     * @author 陈聪
     * @param array $params
     *      user_cust_id:用户在汇付的唯一标识(开户时可为空,其它必传)
     *      business_type:短信类型(101.用户开户,105.解绑快捷卡,201.快捷充值)
     *      mobile:接收短信手机号码
     * @return array $rts
     *      rt:状态码
     *      msg:描述语
     */
    public function sendSms($params){
        $rts=array();
        if(!isset($params['business_type']) || !$params['business_type']){
            $rts['rt']=-1;
            $rts['msg']='短信类型不能为空';
            return $rts;
        }
        if(!isset($params['mobile']) || !$params['mobile']){
            $rts['rt']=-2;
            $rts['msg']='接收短信手机号码不能为空';
            return $rts;
        }
        $data = [
            'version'       => $this->options['version'],
            'cmd_id'        => '110',
            'mer_cust_id'   => $this->options['mer_cust_id'],
            'user_cust_id'  => (isset($params['user_cust_id'])?$params['user_cust_id']:''),
            'order_date'    => date("Ymd"),
            'order_id'      => create_order_sn($params['business_type'],'SMS'),
            'business_type' => $params['business_type'],
            'user_mobile'   => $params['mobile'],
        ];
        //验证结果字段顺序
        $sequence = [
            'cmd_id',
            'resp_code',
            'mer_cust_id',
            'user_cust_id',
            'order_date',
            'order_id',
            'business_type',
            'user_mobile',
        ];
        return $this->_requestInterface($data, $sequence);
    }

    /**
     * @desc 注册开户,涉及101接口
     * @author 陈聪
     * @param array $params
     */
    public function regedit($params){
        $rts=array();
        if(!isset($params['order_date']) || !$params['order_date']){
            $rts['rt']=-1;
            $rts['msg']='订单日期不能为空';
            return $rts;
        }
        if(!isset($params['order_id']) || !$params['order_id']){
            $rts['rt']=-2;
            $rts['msg']='订单编号不能为空';
            return $rts;
        }
        if(!isset($params['card_name']) || !$params['card_name']){
            $rts['rt']=-3;
            $rts['msg']='用户姓名不能为空';
            return $rts;
        }
        if(!isset($params['id_card']) || !$params['id_card']){
            $rts['rt']=-4;
            $rts['msg']='身份证号不能为空';
            return $rts;
        }
        if(!isset($params['mobile']) || !$params['mobile']){
            $rts['rt']=-5;
            $rts['msg']='手机号不能为空';
            return $rts;
        }
        $data = [
            'version'       => $this->options['version'],
            'cmd_id'        => '101',
            'mer_cust_id'   => $this->options['mer_cust_id'],
            'order_date'    => $params['order_date'],
            'order_id'      => $params['order_id'],
            'user_name'     => $params['card_name'],
            'cert_id'       => $params['id_card'],
            'user_mobile'   => $params['mobile'],
            'user_email'    => (isset($params['user_email'])?$params['user_email']:''),
            'sms_code'      => (isset($params['sms_code'])?$params['sms_code']:''),
            'sms_order_date'=> (isset($params['sms_order_date'])?$params['sms_order_date']:''),
            'bg_ret_url'    => $this->options['bg_ret_url'],
            'mer_priv'      => (isset($params['mer_priv'])?$params['mer_priv']:''),
            'extension'     => (isset($params['extension'])?$params['extension']:''),
        ];
        $sequence = [
            'cmd_id',
            'resp_code',
            'mer_cust_id',
            'order_date',
            'order_id',
            'user_cust_id',
            'acct_id',
            'platform_seq_id',
            'fee_amt',
            'fee_acct_id',
            'bg_ret_url',
            'mer_priv',
            'extension',
        ];
        return $this->_requestInterface($data, $sequence);
    }

    /**
     * @desc 预绑定-相当于开户和绑卡发短信-需要做判断,如果已经开户则不用
     *       涉及101、103和110接口
     * @author 陈聪
     */
    public function preBind($params){
        $rts=array();
        if(!isset($params['user_cust_id']) || !$params['user_cust_id']){
            $rts['rt']=-1;
            $rts['msg']='用户标识不能为空';
            return $rts;
        }
        if(!isset($params['order_date']) || !$params['order_date']){
            $rts['rt']=-2;
            $rts['msg']='订单日期不能为空';
            return $rts;
        }
        if(!isset($params['order_sn']) || !$params['order_sn']){
            $rts['rt']=-3;
            $rts['msg']='订单编号不能为空';
            return $rts;
        }
        if(!isset($params['bank_code']) || !$params['bank_code']){
            $rts['rt']=-4;
            $rts['msg']='开户银行代号不能为空';
            return $rts;
        }
        if(!isset($params['bank_card_number']) || !$params['bank_card_number']){
            $rts['rt']=-5;
            $rts['msg']='银行卡号不能为空';
            return $rts;
        }
        if(!isset($params['mobile']) || !$params['mobile']){
            $rts['rt']=-6;
            $rts['msg']='银行预留手机号不能为空';
            return $rts;
        }
        if(!isset($params['bank_province']) || !$params['bank_province']){
            $rts['rt']=-7;
            $rts['msg']='银行卡开户省份不能为空';
            return $rts;
        }
        if(!isset($params['bank_city']) || !$params['bank_city']){
            $rts['rt']=-8;
            $rts['msg']='银行卡开户地区不能为空';
            return $rts;
        }
        $data = [
            'version'       => $this->options['version'],
            'cmd_id'        => '103',
            'mer_cust_id'   => $this->options['mer_cust_id'],
            'user_cust_id'  => $params['user_cust_id'],
            'order_date'    => $params['order_date'],
            'order_id'      => $params['order_sn'],
            'bank_id'       => $params['bank_code'],
            'dc_flag'       => (isset($params['dc_flag'])?$params['dc_flag']:'D'),
            'card_no'       => $params['bank_card_number'],
            'card_mobile'   => $params['mobile'],
            'card_prov'     => $params['bank_province'],
            'card_area'     => $params['bank_city'],
            'ret_url'       => $this->options['ret_url'],
            'bg_ret_url'    => $this->options['bg_ret_url'],
            'mer_priv'      => (isset($params['mer_priv'])?$params['mer_priv']:''),
            'extension'     => (isset($params['extension'])?$params['extension']:''),
        ];
        $sequence = [
            'cmd_id',
            'resp_code',
            'mer_cust_id',
            'user_cust_id',
            'order_date',
            'order_id',
            'platform_seq_id',
            'bank_id',
            'card_no',
            'fee_amt',
            'fee_acct_id',
            'ret_url',
            'bg_ret_url',
            'mer_priv',
            'extension',
        ];

        $rtsA=$this->_requestInterfaceHtml($data);
        if($rtsA['rt']!=1){
            return $rtsA;
        }
        $rtsB=$this->_getHftxBindCardSmsForm($rtsA['response']);
        if(!$rtsB['cookie']){
            $rts['rt']=-9;
            $rts['msg']="短信发送失败";
            return $rts;
        }
        if(!$rtsB['action']){//不能改名字,前端调用需要用它来判断短信是否发送成功
            $rts['rt']=-10;
            $rts['msg']="短信发送失败";
            return $rts;
        }
        if(!$rtsB['smsUrl']){
            $rts['rt']=-11;
            $rts['msg']="短信发送失败";
            return $rts;
        }
        $rtsC=$this->bindCardSendSms($rtsB);
        if($rtsC['rt']!=1){
            return $rtsC;
        }
        $rts['rt']=1;
        $rts['msg']='';
        $rts['data']=$rtsB;
        return $rts;
    }

    /**
     * @desc 绑定银行卡-发送短信
     * @author 陈聪
     */
    public function bindCardSendSms($params){
        $rts=array();
        $ch = curl_init ();
        curl_setopt ( $ch, CURLOPT_REFERER, $this->options['asharpServer'] );
        curl_setopt ( $ch, CURLOPT_USERAGENT, $this->options['useragent'] );
        curl_setopt ( $ch, CURLOPT_URL, $params['smsUrl'] );
        curl_setopt ( $ch, CURLOPT_TIMEOUT, 600 );
        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, false );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, false );
        curl_setopt ( $ch, CURLOPT_COOKIE, $params['cookie'] );
        $str = curl_exec ( $ch );
        if ($str == false) {
            $str = curl_error ( $ch );
        }
        curl_close ( $ch );
        //记录日志
        third_party_api_log($params['smsUrl'],$data,$str,$this->options['type']);
        $rs=json_decode($str,true);
        $rts['rt']=1;
        $rts['msg']='';
        if(!isset($rs['code'])){
            $rts['rt']=-1;
            $rts['msg']=$str;
            return $rts;
        }
        if($rs['code']!='000'){
            $rts['rt']=$rs['code'];
            $rts['msg']=$rs['desc'];
            $rts['result']=$rs['result'];
        }
        return $rts;
    }

    /**
     * @desc 绑定-因为汇付原本是以页面跳转至汇付网站进行相关操作,
     *           所以此处使用curl模拟汇付的post数据提交绑卡
     * @author 陈聪
     * @param array $params
     */
    public function bind($params){
        $params['form']['smsCode']=$params['sms_code'];
        $rts=array();
        $ch = curl_init ();
        curl_setopt ( $ch, CURLOPT_REFERER, $params['action'] );
        curl_setopt ( $ch, CURLOPT_USERAGENT, $this->options['useragent'] );
        curl_setopt ( $ch, CURLOPT_URL, $params['action'] );
        curl_setopt ( $ch, CURLOPT_POST, 1 );
        curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, 'POST' );
        curl_setopt ( $ch, CURLOPT_POSTFIELDS, $params['form'] );
        curl_setopt ( $ch, CURLOPT_TIMEOUT, 600 );
        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, false );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, false );
        curl_setopt ( $ch, CURLOPT_COOKIE, $params['cookie'] );
        $html = curl_exec ( $ch );
        if ($html == false) {
            $html = curl_error ( $ch );
        }
        curl_close ( $ch );
        //记录日志
        third_party_api_log($params['action'],$params,$html,$this->options['type']);
        $rts['rt']=1;
        $rts['msg']='绑定成功!';
        $rts['data']=$this->_getHftxBindCardResult($html);
        if(!isset($rts['data']['resp_code'])||!$rts['data']['resp_code']){
            $rts['rt']=-1;
            $rts['msg']="绑定失败!";
            $rts['data']=$html;
            return $rts;
        }
        if($rts['data']['resp_code']=='103002'){
            $rts['rt']=-2;
            $rts['msg']="请求已受理,请稍后查询!";
            return $rts;
        }
        if($rts['data']['resp_code']!='103000'){
            $rts['rt']=$rts['data']['resp_code'];
            $rts['msg']=urldecode($rts['data']['resp_desc']);
            return $rts;
        }
        return $rts;
    }

    /**
     * @desc 预解绑-涉及110和105接口
     * @author 陈聪
     */
    public function preUnBind($params){
        $params['business_type']='105';
        return $this->sendSms($params);
    }

    /**
     * @desc 解绑-涉及105接口
     *       流程：先发送短信-然后调用本接口
     * @author 陈聪
     * @param array $params
     */
    public function unBind($params){
        $rts=array();
        if(!isset($params['user_cust_id']) || !$params['user_cust_id']){
            $rts['rt']=-1;
            $rts['msg']='用户标识不能为空';
            return $rts;
        }
        if(!isset($params['order_date']) || !$params['order_date']){
            $rts['rt']=-2;
            $rts['msg']='订单日期不能为空';
            return $rts;
        }
        if(!isset($params['order_id']) || !$params['order_id']){
            $rts['rt']=-3;
            $rts['msg']='订单编号不能为空';
            return $rts;
        }
        if(!isset($params['bank_id']) || !$params['bank_id']){
            $rts['rt']=-4;
            $rts['msg']='开户银行代号不能为空';
            return $rts;
        }
        if(!isset($params['bank_card_number']) || !$params['bank_card_number']){
            $rts['rt']=-5;
            $rts['msg']='银行卡号不能为空';
            return $rts;
        }
        if(!isset($params['mobile']) || !$params['mobile']){
            $rts['rt']=-6;
            $rts['msg']='银行预留手机号不能为空';
            return $rts;
        }
        if(!isset($params['sms_code']) || !$params['sms_code']){
            $rts['rt']=-7;
            $rts['msg']='短信验证码不能为空';
            return $rts;
        }
        if(!isset($params['sms_order_date']) || !$params['sms_order_date']){
            $rts['rt']=-8;
            $rts['msg']='短信验证码日期不能为空';
            return $rts;
        }
        if(!isset($params['sms_order_id']) || !$params['sms_order_id']){
            $rts['rt']=-9;
            $rts['msg']='短信验证码订单ID不能为空';
            return $rts;
        }
        $data = [
            'version'       => $this->options['version'],
            'cmd_id'        => '105',
            'mer_cust_id'   => $this->options['mer_cust_id'],
            'user_cust_id'  => $params['user_cust_id'],
            'order_date'    => $params['order_date'],
            'order_id'      => $params['order_id'],
            'bank_id'       => $params['bank_id'],
            'card_no'       => $params['bank_card_number'],
            'card_mobile'   => $params['mobile'],
            'sms_code'      => $params['sms_code'],
            'sms_order_date'=> $params['sms_order_date'],
            'sms_order_id'  => $params['sms_order_id'],
            'bg_ret_url'    => $this->options['bg_ret_url'],
            'mer_priv'      => (isset($params['mer_priv'])?$params['mer_priv']:''),
            'extension'     => (isset($params['extension'])?$params['extension']:''),
        ];
        $sequence = [
            'cmd_id',
            'resp_code',
            'mer_cust_id',
            'user_cust_id',
            'order_date',
            'order_id',
            'bank_id',
            'card_no',
            'card_mobile',
            'sms_code',
            'sms_order_date',
            'sms_order_id',
            'bg_ret_url',
            'mer_priv',
            'extension',
        ];
        return $this->_requestInterface($data, $sequence);
    }

    /**
     * @desc 查询绑卡状态
     * @author 陈聪
     * @param array $data
     */
    public function queryBindStatus($params){
        $rts=array();
        $rts['rt']=-1;
        $rts['msg']='汇付暂无相关接口';
        return $rts;
    }

    /**
     * @desc 预支付-此处为发送短信
     * @author 陈聪
     * @param array $params
     *              user_cust_id:汇付用户ID
     *              mobile:银行预留手机号码
     */
    public function prePay($params){
        $params['business_type']='201';
        return $this->sendSms($params);
    }

    /**
     * @desc 支付-涉及201接口
     * @author 陈聪
     */
    public function pay($params){
        $rts=array();
        if(!isset($params['user_cust_id']) || !$params['user_cust_id']){
            $rts['rt']=-1;
            $rts['msg']='用户标识不能为空';
            return $rts;
        }
        if(!isset($params['order_date']) || !$params['order_date']){
            $rts['rt']=-2;
            $rts['msg']='订单日期不能为空';
            return $rts;
        }
        if(!isset($params['order_id']) || !$params['order_id']){
            $rts['rt']=-3;
            $rts['msg']='订单编号不能为空';
            return $rts;
        }
        $params['trans_amt']=(isset($params['trans_amt'])?floatval($params['trans_amt']):0);
        if($params['trans_amt']<100){
            $rts['rt']=-4;
            $rts['msg']='充值金额不合法!';
            return $rts;
        }
        $params['trans_amt']=sprintf("%.2f",$params['trans_amt']);//这句话要写在判断之后,原来是float,此处需要格式化成string
        if(!isset($params['sms_code']) || !$params['sms_code']){
            $rts['rt']=-5;
            $rts['msg']='短信验证码不能为空';
            return $rts;
        }
        if(!isset($params['sms_order_date']) || !$params['sms_order_date']){
            $rts['rt']=-6;
            $rts['msg']='短信验证码日期不能为空';
            return $rts;
        }
        if(!isset($params['sms_order_id']) || !$params['sms_order_id']){
            $rts['rt']=-7;
            $rts['msg']='短信验证码ID不能为空';
            return $rts;
        }

        $data = [
            'version'       => $this->options['version'],
            'cmd_id'        => '201',
            'mer_cust_id'   => $this->options['mer_cust_id'],
            'user_cust_id'  => $params['user_cust_id'],
            'order_date'    => $params['order_date'],
            'order_id'      => $params['order_id'],
            'trans_type'    => (isset($params['trans_type'])?$params['trans_type']:'02020101'),
            'recharge_type' => (isset($params['recharge_type'])?$params['recharge_type']:'02020002'),
            'trans_amt'     => $params['trans_amt'],
            'bank_id'       => (isset($params['bank_id'])?$params['bank_id']:''),
            'dc_flag'       => (isset($params['dc_flag'])?$params['dc_flag']:'D'),
            'sms_code'      => $params['sms_code'],
            'sms_order_date'=> $params['sms_order_date'],
            'sms_order_id'  => $params['sms_order_id'],
            'sign_seq_id'   => (isset($params['sign_seq_id'])?$params['sign_seq_id']:''),
            'in_cust_id'    => (isset($params['in_cust_id'])?$params['in_cust_id']:$this->options['mer_cust_id']),
            'div_detail'    => '[{"div_acct_id":"'.$this->options['acct_id'].'","div_amt":"'.$params['trans_amt'].'"}]',
            'ret_url'       => $this->options['ret_url'],
            'bg_ret_url'    => $this->options['bg_ret_url'],
            'mer_priv'      => (isset($params['mer_priv'])?$params['mer_priv']:''),
            'extension'     => (isset($params['extension'])?$params['extension']:''),
            'card_no'       => (isset($params['card_no'])?$params['card_no']:''),
        ];
        $sequence=array(
            'cmd_id',
            'resp_code',
            'mer_cust_id',
            'user_cust_id',
            'order_date',
            'order_id',
            'platform_seq_id',
            'trans_type',
            'recharge_type',
            'trans_amt',
            'bank_id',
            'dc_flag',
            'sms_code',
            'sms_order_date',
            'sms_order_id',
            'sign_seq_id',
            'in_cust_id',
            'div_detail',
            'fee_amt',
            'fee_cust_id',
            'fee_acct_id',
            'ret_url',
            'bg_ret_url',
            'mer_priv',
            'extension'
        );
        return $this->_requestInterface($data,$sequence);
    }

    /**
     * @desc 商户转账给用户-涉及203接口
     * @author 陈聪
     */
    public function b2c($params){
        $rts=array();
        if(!isset($params['order_date']) || !$params['order_date']){
            $rts['rt']=-1;
            $rts['msg']='订单日期不能为空';
            return $rts;
        }
        if(!isset($params['order_id']) || !$params['order_id']){
            $rts['rt']=-2;
            $rts['msg']='订单编号不能为空';
            return $rts;
        }
        if(!isset($params['in_cust_id']) || !$params['in_cust_id']){
            $rts['rt']=-3;
            $rts['msg']='用户标识不能为空';
            return $rts;
        }
        if(!isset($params['in_acct_id']) || !$params['in_acct_id']){
            $rts['rt']=-4;
            $rts['msg']='用户子账户ID不能为空';
            return $rts;
        }
        $params['transfer_amt']=(isset($params['transfer_amt'])?floatval($params['transfer_amt']):0);
        if($params['transfer_amt']<=0){
            $rts['rt']=-5;
            $rts['msg']='转账金额不合法!';
            return $rts;
        }
        $params['transfer_amt']=sprintf("%.2f",$params['transfer_amt']);//这句话要写在判断之后,原来是float,此处需要格式化成string

        $data = [
            'version'       => $this->options['version'],
            'cmd_id'        => '203',
            'mer_cust_id'   => $this->options['mer_cust_id'],
            'order_date'    => $params['order_date'],
            'order_id'      => $params['order_id'],
            'transfer_type' => (isset($params['transfer_type'])?$params['transfer_type']:'02040000'),
            'out_cust_id'   => $this->options['mer_cust_id'],
            'out_acct_id'   => $this->options['acct_id'],
            'in_cust_id'    => $params['in_cust_id'],
            'in_acct_id'    => $params['in_acct_id'],
            'transfer_amt'  => $params['transfer_amt'],
            'bg_ret_url'    => $this->options['bg_ret_url'],
            'mer_priv'      => (isset($params['mer_priv'])?$params['mer_priv']:''),
            'extension'     => (isset($params['extension'])?$params['extension']:''),
        ];

        $sequence = [
            'cmd_id',
            'resp_code',
            'mer_cust_id',
            'order_date',
            'order_id',
            'transfer_type',
            'out_cust_id',
            'out_acct_id',
            'in_cust_id',
            'in_acct_id',
            'transfer_amt',
            'bg_ret_url',
            'mer_priv',
            'extension',
        ];
        return $this->_requestInterface($data, $sequence);
    }

    /**
     * @desc 提现
     * @author 陈聪
     */
    public function withdraw($params){
        $rts=array();
        if(!isset($params['order_date']) || !$params['order_date']){
            $rts['rt']=-1;
            $rts['msg']='订单日期不能为空';
            return $rts;
        }
        if(!isset($params['order_id']) || !$params['order_id']){
            $rts['rt']=-2;
            $rts['msg']='订单编号不能为空';
            return $rts;
        }
        $params['trans_amt']=(isset($params['trans_amt'])?floatval($params['trans_amt']):0);
        if($params['trans_amt']<=0){
            $rts['rt']=-3;
            $rts['msg']='提现金额不合法!';
            return $rts;
        }
        $params['trans_amt']=sprintf("%.2f",$params['trans_amt']);//这句话要写在判断之后,原来是float,此处需要格式化成string

        $data = [
            'version'       => $this->options['version'],
            'cmd_id'        => '203',
            'mer_cust_id'   => $this->options['mer_cust_id'],
            'user_cust_id'  => $params['user_cust_id'],
            'order_date'    => $params['order_date'],
            'order_id'      => $params['order_id'],
            'trans_amt'     => $params['trans_amt'],
            'card_no'       => (isset($params['card_no'])?$params['card_no']:''),
            'cash_deduct_type' => (isset($params['cash_deduct_type'])?$params['cash_deduct_type']:'02030100'),
            'serv_fee_amt'  => (isset($params['serv_fee_amt'])?$params['serv_fee_amt']:''),
            'serv_fee_acct_id' => (isset($params['serv_fee_acct_id'])?$params['serv_fee_acct_id']:''),
            'fee_obj'       => (isset($params['fee_obj'])?$params['fee_obj']:''),
            'fee_acct_id'   => (isset($params['fee_acct_id'])?$params['fee_acct_id']:''),
            'cash_type'     => (isset($params['cash_type'])?$params['cash_type']:'02030010'),
            'bg_ret_url'    => $this->options['bg_ret_url'],
            'mer_priv'      => (isset($params['mer_priv'])?$params['mer_priv']:''),
            'extension'     => (isset($params['extension'])?$params['extension']:''),
        ];

        $sequence = [
            'cmd_id',
            'resp_code',
            'mer_cust_id',
            'user_cust_id',
            'order_date',
            'order_id',
            'platform_seq_id',
            'trans_amt',
            'real_trans_amt',
            'card_no',
            'cash_deduct_type',
            'bank_id',
            'serv_fee_amt',
            'serv_fee_acct_id',
            'fee_amt',
            'fee_cust_id',
            'fee_acct_id',
            'bg_ret_url',
            'mer_priv',
            'extension',
        ];
        return $this->_requestInterface2($data, $sequence);
    }

    /**
     * @desc 查询订单状态-涉及301接口
     * @author 陈聪
     */
    public function queryPayStatus($params){
        $params['trans_type']='05000009';
        return $this->queryOrderStatus($params);
    }

    /**
     * @desc 查询订单状态-涉及301接口-主要是快捷支付/B2C/T0取现/T1取现
     * @author 陈聪
     * @params array $params
     *         trans_type:
     *              05000009 快捷支付
     *              05000005 B2C转账
     *              05000003 T0取现
     *              05000004 T1取现
     */
    public function queryOrderStatus($params){
        $rts=array();
        if(!isset($params['order_date']) || !$params['order_date']){
            $rts['rt']=-1;
            $rts['msg']='订单日期不能为空';
            return $rts;
        }
        if(!isset($params['order_id']) || !$params['order_id']){
            $rts['rt']=-2;
            $rts['msg']='订单编号不能为空';
            return $rts;
        }
        if(!isset($params['trans_type']) || !$params['trans_type']){
            $rts['rt']=-3;
            $rts['msg']='订单类型';
            return $rts;
        }
        $data = [
            'version'       => $this->options['version'],
            'cmd_id'        => '301',
            'mer_cust_id'   => $this->options['mer_cust_id'],
            'order_date'    => $params['order_date'],
            'order_id'      => $params['order_id'],
            'trans_type'     => $params['trans_type'],
        ];

        $sequence = [
            'cmd_id',
            'resp_code',
            'mer_cust_id',
            'order_date',
            'order_id',
            'platform_seq_id',
            'trans_type',
            'trans_stat',
            'trans_amt',
            'fee_amt',
            'fee_acct_id',
            'frz_flag',
        ];
        return $this->_requestInterface($data, $sequence);
    }

    /**
     * @desc 余额信息查询-涉及302接口
     * @author 陈聪
     */
    public function queryBalanceInfo($params){
        $rts=array();
        if(!isset($params['user_cust_id']) || !$params['user_cust_id']){
            $rts['rt']=-1;
            $rts['msg']='用户Id不能为空';
            return $rts;
        }
        $data = [
            'version'       => $this->options['version'],
            'cmd_id'        => '302',
            'mer_cust_id'   => $this->options['mer_cust_id'],
            'user_cust_id'    => $params['user_cust_id'],
        ];
        $sequence = [
            'cmd_id',
            'resp_code',
            'mer_cust_id',
            'user_cust_id',
            'balance',
            'cash_balance',
            'acct_balance',
            'freeze_balance',
        ];
        return $this->_requestInterface($data, $sequence);
    }
}